#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netpacket/packet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define MAX 1024
#define ERR(errmsg) do{\
                        perror(errmsg);\
                        exit(-1);\
                    }while(0)

int main(int argc, char const *argv[])
{
    //ARP组包
    unsigned char msg[MAX] = {
        0xff,0xff,0xff,0xff,0xff,0xff,     //目的mac地址（广播）
        0x00,0x0c,0x29,0xd0,0x33,0x73,     //源mac地址
        0x08,0x06,                         //帧类型（ARP数据报）
        0x00,0x01,                         //硬件类型（以太网地址：1）
        0x08,0x00,                         //地址类型（ip地址）
        6,                                 //硬件地址长度
        4,                                 //ip地址长度
        0x00,0x01,                         //OP（1：ARP请求）
        0x00,0x0c,0x29,0xd0,0x33,0x73,     //源mac地址
        192,168,125,129,                   //源ip地址
        0x00,0x00,0x00,0x00,0x00,0x00,     //目的mac地址（未知，一般设0）
        192,168,125,1                      //目的ip地址
    };

    int sock_raw_fd;
    //创建原始套接字
    if((sock_raw_fd = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) < 0)
    {
        ERR("fail to socket");
    }

    //获取网络接口
    struct ifreq ethreq;
    strncpy(ethreq.ifr_ifrn.ifrn_name,"ens32",IFNAMSIZ);
    if(ioctl(sock_raw_fd,SIOCGIFINDEX,&ethreq) < 0)
    {
        ERR("fail to ioctl");
    }

    //获取网络接口地址，给接口类型赋值
    struct sockaddr_ll sll;
    bzero(&sll,sizeof(sll));
    sll.sll_ifindex = ethreq.ifr_ifru.ifru_ivalue;

    //发送套接字数据
    if(sendto(sock_raw_fd,msg,14+28,0,(struct sockaddr*)&sll,sizeof(sll)) < 0)
    {
        ERR("fail to sendto");
    }

    //接收mac地址
    unsigned char buf_recv[MAX] = "";
    unsigned char src_mac[18] = "";
    while(1)
    {
        //获取目的主机的ARP应答
        if(recvfrom(sock_raw_fd,buf_recv,MAX,0,NULL,NULL) < 0)
        {
            ERR("fail to recvfrom");
        }
        //判断是否为ARP数据报
        if(ntohs(*(unsigned short*)(buf_recv+12)) == 0x0806)
        {
            //为ARP数据报的前提下，再判断是否为ARP应答（OP == 2）
            if(ntohs(*(unsigned short*)(buf_recv+20)) == 2)
            {
                //获取目的主机mac地址
                //注意：由于是对方（目的主机）的应答，所以要获取的想要的目的mac地址，实际是接收到的ARP数据报的源mac地址
                sprintf(src_mac,"%x:%x:%x:%x:%x:%x",buf_recv[6],buf_recv[7],buf_recv[8],buf_recv[9],buf_recv[10],buf_recv[11]);
                printf("dest_ip: %d.%d.%d.%d -- dest_mac: %s\n",msg[38],msg[39],msg[40],msg[41],src_mac);
                break;
            }
        }
    }
    //关闭原始套接字
    close(sock_raw_fd);
    return 0;
}
